/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.designtime.generator.metadatacompile;

import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bef.bizentity.operation.BizMgrAction;
import com.inspur.edp.bef.bizentity.operation.BizOperation;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import com.inspur.edp.formserver.viewmodel.action.ViewModelAction;
import com.inspur.edp.formserver.viewmodel.action.ViewModelActionType;
import com.inspur.edp.formserver.viewmodel.collection.VMActionCollection;
import com.inspur.edp.jittojava.context.JitContext;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import io.iec.edp.caf.commons.exception.CAFRuntimeException;
import io.iec.edp.caf.commons.exception.ExceptionLevel;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public
class VmCoincidenceCheck {

  protected GspViewModel viewModel;
  protected JitContext jitContext;
  protected HashMap<String, GspBusinessEntity> relatedBizEntityDic;
  protected StringBuffer exceptionMessage;
  protected int countExpression;


  public VmCoincidenceCheck(JitContext context) {
    this.jitContext = context;
    this.viewModel = (GspViewModel) context.getMetadata().getContent();
    this.exceptionMessage = new StringBuffer();
    this.relatedBizEntityDic = new HashMap<>();
    this.countExpression = 0;
  }


  public void checkVmAndBeCoincidence() {
    if (this.viewModel.getIsVirtual()) {
      return;
    }
    checkObjects(this.viewModel.getAllObjectList());
    compareMgrActionCollection();
    showExceptions();

  }

  //将ViewModel的异常信息全部打出来
  protected void showExceptions() {

    if (this.exceptionMessage.toString() == null
        || this.exceptionMessage.toString().length() == 0) {
      return;
    }
    this.exceptionMessage.append("  请重新打开VO保存！");
//    try{
//      throw new CAFRuntimeException("", "0001", "VO和BE一致性校验异常，详细信息见控制台。", null,
//          ExceptionLevel.Error, true);
//    }catch (CAFRuntimeException e){
//     throw new RuntimeException(addNumExceptionMessage(this.exceptionMessage.toString()),e);
//    }
    throw new CAFRuntimeException("", "0001",
        addNumExceptionMessage(this.exceptionMessage.toString()), null,
        ExceptionLevel.Error, true);
  }

  private String addNumExceptionMessage(String message) {
    String sToFind = "ErrorNum";
    Pattern p = Pattern.compile("ErrorNum");
    int count = 1;
    while (message.contains(sToFind)) {
      Matcher m = p.matcher(message);
      message = m.replaceFirst(String.valueOf(count++));
    }
    return message;
  }

  //检查对应Vo上所有节点
  protected void checkObjects(ArrayList<IGspCommonObject> viewObjects) {
    if (viewObjects == null || viewObjects.size() == 0) {
      return;
    }
    for (IGspCommonObject viewObject : viewObjects) {
      if (viewObject.getIsVirtual()) {
        continue;
      }
      VmObjectCoincidenceCheck objectCoincidenceCheck = new VmObjectCoincidenceCheck(
          this.jitContext, viewObject, this.relatedBizEntityDic);
      String ObjectExceptionMessage = objectCoincidenceCheck.checkCurrentObject();
      if (ObjectExceptionMessage == null || ObjectExceptionMessage.equals("")) {
        continue;
      }
      this.exceptionMessage.append(ObjectExceptionMessage);
    }
  }

  //比较自定义动作: id & returnType
  protected void compareMgrActionCollection() {
    VMActionCollection viewModelActions = this.viewModel.getActions();

    GspBusinessEntity businessEntity = getViewObjectRelatedBizEntity(
        this.viewModel.getMainObject());
    for (ViewModelAction vmAction : viewModelActions) {
      //判断ViewModel动作是否有对应的BE动作
      if (!vmAction.getType().equals(ViewModelActionType.BEAction)) {
        continue;
      }
      BizOperation bizMgrAction = getRelatedMgrAction(vmAction, businessEntity);
      if (bizMgrAction == null || ((BizMgrAction) bizMgrAction).getReturnValue() == null) {
        this.exceptionMessage.append(CheckCoincidenceException
            .throwVOMgrActionException(this.viewModel, vmAction, businessEntity));
        continue;
      }
      if (!vmAction.getReturnValue().getClassName()
          .equals(((BizMgrAction) bizMgrAction).getReturnValue().getClassName())) {
        this.exceptionMessage.append(CheckCoincidenceException
            .throwVOMgrActionReturnValue(this.viewModel, vmAction, businessEntity,
                (BizMgrAction) bizMgrAction));
        continue;
      }
    }
  }

  //根据Mapping找到对应的BE MgrAction
  protected BizOperation getRelatedMgrAction(ViewModelAction vmAction,
      GspBusinessEntity businessEntity) {
    if (vmAction.getMapping() == null) {
      this.exceptionMessage.append(CheckCoincidenceException
          .throwVOMgrActionException(this.viewModel, vmAction, businessEntity));
      return null;
    }

    String relatedMgrActionId = vmAction.getMapping().getTargetObjId();
    BizOperation bizMgrAction = null;
    for (BizOperation bizOperation : businessEntity.getBizMgrActions()) {
      if (bizOperation.getID().equals(relatedMgrActionId)) {
        bizMgrAction = bizOperation;
        break;
      }
    }
    return bizMgrAction;
  }

  //获取Mapping BE
  protected GspBusinessEntity getViewObjectRelatedBizEntity(IGspCommonObject viewObject) {
    if (!(viewObject instanceof GspViewObject)) {
      this.exceptionMessage
          .append(CheckCoincidenceException.throwObjectDataTypeException(viewObject.getCode()));
    }
    if (((GspViewObject) viewObject).getMapping() == null) {
      this.exceptionMessage.append(CheckCoincidenceException
          .throwVmObjectMappingException(this.viewModel, viewObject));
    }
    String relateMetadataId = ((GspViewObject) viewObject).getMapping().getTargetMetadataId();
    //首先检查dic中是否有GspBusinessEntity
    return getBizEntityByMetadataId(relateMetadataId, viewObject);
  }

  protected GspBusinessEntity getBizEntityByMetadataId(String relateMetadataId,
      IGspCommonObject viewObject) {
    GspBusinessEntity businessEntity = null;
    if (this.relatedBizEntityDic.containsKey(relateMetadataId)) {
      return relatedBizEntityDic.get(relateMetadataId);
    }
    GspMetadata gspmetadata = this.jitContext.getMetadata(relateMetadataId);
    if (gspmetadata.getContent() == null || !(gspmetadata
        .getContent() instanceof GspBusinessEntity)) {
      this.exceptionMessage.append(
          CheckCoincidenceException.throwBizEntityNotFindException(this.viewModel, viewObject));
    }
    businessEntity = (GspBusinessEntity) gspmetadata.getContent();
    this.relatedBizEntityDic.put(relateMetadataId, businessEntity);
    return businessEntity;
  }

}
